package com.authsphere.security.configurer.social.configurers;

import com.authsphere.plugin.api.AuthSphereAfterPluginChain;
import com.authsphere.plugin.api.AuthSphereBeforePluginChain;
import com.authsphere.security.common.configurers.AbstractAuthSphereAuthenticationFilterConfigurer;
import com.authsphere.security.common.user.DefaultEnhanceUserDetailsService;
import com.authsphere.security.common.user.EnhanceUserDetailsService;
import com.authsphere.security.configurer.social.filter.ThirdAuthorizationRequestBodyAuthenticationFilter;
import com.authsphere.security.configurer.social.provider.ThirdAuthorizationAuthenticationProvider;
import com.authsphere.security.web.handler.AuthenticationHandler;
import me.zhyd.oauth.cache.AuthDefaultStateCache;
import me.zhyd.oauth.cache.AuthStateCache;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.ResolvableType;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/11 17:02
 **/
public class ThirdAuthorizationAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>> extends
        AbstractAuthSphereAuthenticationFilterConfigurer<H, ThirdAuthorizationAuthenticationFilterConfigurer<H>, ThirdAuthorizationRequestBodyAuthenticationFilter> {

    private String processingUrl;

    private AuthenticationHandler authenticationHandler;

    public ThirdAuthorizationAuthenticationFilterConfigurer() {
        super(UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
        return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    }

    private final static String DEFAULT_BIND_REDIRECT_URL = "/third/bind";
    private final static String DEFAULT_MODULE_NAME = "third_login";
    private final static String DEFAULT_APP_CLIENT_HEADER = "User-Agent";
    private final static String DEFAULT_APP_CLIENT_VALUE = "AppClient";
    private String bindRedirectUrl = DEFAULT_BIND_REDIRECT_URL;
    private String moduleName = DEFAULT_MODULE_NAME;
    private String appClientHeader = DEFAULT_APP_CLIENT_HEADER;
    private String appClientValue = DEFAULT_APP_CLIENT_VALUE;
    @Override
    public void init(H http) throws Exception {
        ThirdAuthorizationRequestBodyAuthenticationFilter authenticationFilter = new ThirdAuthorizationRequestBodyAuthenticationFilter(getAuthStateCache());
        authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
        if (StringUtils.isNotBlank(processingUrl)) {
            authenticationFilter.setFilterProcessesUrl(processingUrl);
        }
        authenticationFilter.setBindUrl(bindRedirectUrl);
        authenticationFilter.setModuleName(moduleName);
        authenticationFilter.setAppClientHeader(appClientHeader);
        authenticationFilter.setAppClientValue(appClientValue);

        authenticationFilter.setAuthenticationHandler(getAuthenticationHandler(http));
        this.setAuthenticationFilter(authenticationFilter);
        EnhanceUserDetailsService userDetailsService = getUserDetailsService();
        ThirdAuthorizationAuthenticationProvider thirdAuthorizationAuthenticationProvider = new ThirdAuthorizationAuthenticationProvider();
        thirdAuthorizationAuthenticationProvider.setUserDetailsService(userDetailsService);
        http.authenticationProvider(this.postProcess(thirdAuthorizationAuthenticationProvider));
    }

    private AuthenticationHandler getAuthenticationHandler(H http) {
        if (authenticationHandler != null) {
            return authenticationHandler;
        }
        return http.getSharedObject(AuthenticationHandler.class);
    }

    private EnhanceUserDetailsService getUserDetailsService() {
        ResolvableType type = ResolvableType.forType(EnhanceUserDetailsService.class);
        EnhanceUserDetailsService bean = getBeanOrNull(type);
        return (bean != null) ? bean : new DefaultEnhanceUserDetailsService();
    }


    private AuthStateCache getAuthStateCache() {
        ResolvableType type = ResolvableType.forType(AuthStateCache.class);
        AuthStateCache bean = getBeanOrNull(type);
        return (bean != null) ? bean : AuthDefaultStateCache.INSTANCE;
    }



    public ThirdAuthorizationAuthenticationFilterConfigurer<H> processingUrl(String processingUrl) {
        this.processingUrl = processingUrl;
        return this;
    }

    public ThirdAuthorizationAuthenticationFilterConfigurer<H> bindRedirectUrl(String bindRedirectUrl) {
        this.bindRedirectUrl = bindRedirectUrl;
        return this;
    }

    public ThirdAuthorizationAuthenticationFilterConfigurer<H> moduleName(String moduleName) {
        this.moduleName = moduleName;
        return this;
    }

    public ThirdAuthorizationAuthenticationFilterConfigurer<H> appClientHeader(String appClientHeader) {
        this.appClientHeader = appClientHeader;
        return this;
    }

    public ThirdAuthorizationAuthenticationFilterConfigurer<H> appClientValue(String appClientValue) {
        this.appClientValue = appClientValue;
        return this;
    }


    public ThirdAuthorizationAuthenticationFilterConfigurer<H> setAuthenticationHandler(AuthenticationHandler authenticationHandler) {
        this.authenticationHandler = authenticationHandler;
        return this;
    }
}
